Skip to content

feat: uninstall installed plugins (#37) - #228

Merged
matheuswhite merged 1 commit into
mainfrom
feat/37-uninstall-plugin
Jul 27, 2026
Merged

feat: uninstall installed plugins (#37)#228
matheuswhite merged 1 commit into
mainfrom
feat/37-uninstall-plugin

Conversation

@matheuswhite

Copy link
Copy Markdown
Owner

What

Closes #37. Adds !plugin uninstall <name>, the inverse of !plugin install (#36): it removes the plugin from the persistent manifest and deletes its staged copy, so it no longer auto-loads at start-up. !plugin list shows the remaining set.

!plugin uninstall analytics   # drop from the auto-load set + delete staged copy

It is orthogonal to !plugin unload: uninstall changes only the persistent set — a plugin already loaded this session stays active until you !plugin unload it or restart. (Decided with the issue author.)

How

  • src/plugin/engine.rsPluginEngineCommand::UninstallPlugin. The handler normalizes the name (foo / foo.lua both work via get_plugin_name), errors if the plugin isn't installed, updates the manifest, then deletes the staged <name>.lua. A missing file is tolerated; other IO errors warn but don't abort (the manifest, which drives auto-load, is already updated).
  • Stdlib-deletion guard — the deletion never targets a bundled STDLIB file (scope.lua / shell.lua). !plugin install rejects reserved names, so a manifest listing one can only come from a hand-edited file; silently losing a user-customized scope.lua to it would be a nasty surprise, so the file is preserved (the bogus manifest entry is still cleaned). This closed the one defense-in-depth gap flagged by an adversarial review of the diff.
  • src/plugin/installed.rsInstalled::remove (returns whether it was present).
  • src/inputs/inputs_task.rs — the !plugin handler gains the uninstall subcommand (arg-required), alongside the existing load/reload/install/list/unload.
  • Docs: README command table + Plugins prose, CLAUDE.md, plugins/README.md.

Tests

  • installed.rs unit test for remove (presence reporting + dedup-safety).
  • tests/tui_e2e.rs:
    • uninstall removes the manifest entry and deletes the staged file;
    • uninstalling something not installed is a clear error;
    • the stdlib-safety guard: a corrupt manifest listing scope has the entry cleaned but scope.lua survives.

All 232 unit + 23 e2e tests pass (1 e2e ignored on macOS per the existing PTY-baud limitation); tree is warning-clean under #![deny(warnings)].

🤖 Generated with Claude Code

Add `!plugin uninstall <name>`, the inverse of `!plugin install` (#36): it
removes the plugin from the persistent manifest and deletes its staged copy, so
it no longer auto-loads at start-up. It is orthogonal to `!plugin unload` — it
does NOT stop a running instance (a plugin already loaded this session stays
active until `!plugin unload` or restart); the single "uninstalled" log
reflects only the change to the persistent set.

The engine grows `PluginEngineCommand::UninstallPlugin`: it normalizes the name
(`foo`/`foo.lua` both work), errors if the plugin isn't installed, updates the
manifest, then deletes the staged `<name>.lua`. It never deletes a bundled
STDLIB file (`scope.lua`/`shell.lua`): install rejects reserved names, so such
an entry can only come from a hand-edited manifest, and silently losing a
user-customized `scope.lua` to it would be a nasty surprise — the manifest entry
is still cleaned. `Installed` gains `remove`; the `!plugin` command handler
gains the `uninstall` subcommand.

Tests: a manifest `remove` unit test; e2e for uninstall (manifest entry + staged
file gone), uninstalling something not installed (error), and the stdlib-safety
guard (a corrupt manifest listing `scope` cleans the entry but keeps scope.lua).

Co-Authored-By: Claude Opus 4.8 (1M context) <[email protected]>
@matheuswhite
matheuswhite merged commit 5bac850 into main Jul 27, 2026
8 checks passed
@matheuswhite
matheuswhite deleted the feat/37-uninstall-plugin branch July 27, 2026 12:51
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Add a command to uninstall a plugin

1 participant